package completeFurther;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author hepei
 * @date 2019/8/26 10:05
 **/
@Slf4j
public class CompletableFutureDemo {

    /***
     * 无返回值
     */
    private static void runAsync() throws ExecutionException, InterruptedException {
        log.info("start ...{}",  System.currentTimeMillis()  );
        CompletableFuture<Void> future = CompletableFuture.runAsync( () -> {
            try {
                TimeUnit.SECONDS.sleep( 1 );
            } catch (InterruptedException ignored) {
            }
            log.info("end .....{}",  System.currentTimeMillis()  );
        } );
        TimeUnit.SECONDS.sleep( 2 );
       // future.get();
    }

    /***
     * 有返回值
     */
    private static void supplyAsync() throws ExecutionException, InterruptedException {
        log.info("start ...{}",  System.currentTimeMillis()  );
        CompletableFuture<Long> future = CompletableFuture.supplyAsync( () -> {
            try {
                TimeUnit.SECONDS.sleep( 1 );
            } catch (InterruptedException ignored) {
            }
            log.info("end .....{}",  System.currentTimeMillis()  );
            return System.currentTimeMillis();
        } );

        Long aLong = future.get();
        log.info("currentTime:{}",  System.currentTimeMillis());
    }


    private static void whenComplete() throws InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.runAsync( () -> {
            try {
                TimeUnit.SECONDS.sleep( 1 );
            } catch (InterruptedException ignored) {
            }
            log.info("start ...{}",  System.currentTimeMillis()  );
            int i = 1 / 0;
        } );
        // 执行当前任务的线程执行继续执行 whenComplete 的任务
        future.whenComplete( (aVoid, throwable) -> log.info("执行完成{}", throwable.getMessage()) );
        //当future执行发生异常后执行
        future.exceptionally( throwable -> {
            log.info("执行发生异常:{}", throwable.getMessage());
            return null;
        } );
        TimeUnit.SECONDS.sleep( 2 );
    }

    /***
     * 第二个任务依赖第一个任务的结果
     * thenApply 只可以执行正常的任务，任务出现异常则不执行 thenApply 方法
     */
    private static void thenApply() throws ExecutionException, InterruptedException {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync( () -> {
            long data = new Random().nextInt( 100 );
            log.info("data1=:{}", data);
            return data;
        } ).thenApply( t -> {
            long data = t * 10;
            log.info("data2=:{}", data);
            String a = null;
            a.toCharArray();
            return data;
        } /*).exceptionally( throwable -> {
            log.info("执行发生异常:{}", throwable.getMessage());
            throw new RuntimeException();
           
        } */);
        long result = future.get();
        log.info("thenApply执行结果:{}", result);
    }

    /***
     * 任务完成后再执行，还可以处理异常的任务
     */
    private static void handle() throws ExecutionException, InterruptedException {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync( () -> {
            int i = 10 / 0;
            return new Random().nextLong();
        } ).handle( (param, throwable) -> {
            Long result = -1L;
            if (throwable == null) {
                result = param * 10;
            } else {
                log.info("执行发生异常:{}", throwable.getMessage());
            }
            return result;
        } );
        log.info("handle执行结果:{}", future.get());
    }

    /***
     * 接收任务的处理结果，并消费处理，无返回结果。
     */
    private static void thenAccept() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync( () -> new Random().nextInt( 1000 ) ).
                thenAccept( aLong -> log.info("thenAccept接收aLong值:{}",aLong) );
        future.get();
    }

    /***
     * 不关心任务的处理结果。只要上面的任务执行完成，就开始执行 thenRun 。
     */
    private static void thenRun() throws ExecutionException, InterruptedException {
        CompletableFuture future = CompletableFuture.supplyAsync( () ->{ 
        		try {
					new Thread(new Runnable(){

						@Override
						public void run() {
							try {
								Thread.sleep(100000);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						
					}).start();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        		return new Random().nextInt( 10 );
        	}).thenRun( () ->  log.info("开始执行thenRun()"));
        future.get();
    }

    /***
     * 把两个任务的结果一块交给 thenCombine 来处理
     */
    private static void thenCombine() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync( () -> "then" );
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync( () -> "Combine" );
        CompletableFuture<String> data = future1.thenCombine( future2, (s, s2) -> s + " " + s2 );
        log.info("thenCombine执行结果:{}",data.get());
    }

    /***
     * 当两个CompletionStage都执行完成后，把结果一块交给thenAcceptBoth来进行消耗
     */
    private static void thenAcceptBoth()  {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 3 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future1结果:{}",t);
            return t;
        } );

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 3 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future2结果:{}",t);
            return t;
        } );

        future1.thenAcceptBoth( future2, (integer, integer2) -> log.info("thenAcceptBoth:当两个任务都执行完后汇总，" +
                " future1结果:{},future2的结果:{}",integer,integer2) );
    }

    /***
     * 两个CompletionStage，谁执行返回的结果快，就用那个CompletionStage的结果进行下一步的转化操作。
     */
    private static void applyToEither()  {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 4 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future1结果:{}",t);
            return t;
        } );
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 4 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future2结果:{}",t);
            return t;
        } );

        CompletableFuture<Integer> result = future1.applyToEither( future2, t -> {
            log.info("applyToEither接收到第一个完成任务的结果是:{}",t);
            return t * 2;
        } );
        log.info( "applyToEither最终结果是:{}",result );
    }

    /***
     * 两个CompletionStage，谁执行返回的结果快，我就用那个CompletionStage的结果进行下一步的消耗操作。
     */
    private static void acceptEither() {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 5 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future1结果:{}",t);
            return t;
        } );

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 5 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future2结果:{}",t);
            return t;
        } );
        future1.acceptEither( future2, t -> log.info("acceptEither接收到第一个完成任务的结果是:{}",t) );
    }

    /***
     * 两个CompletionStage，任何一个完成了都会执行下一步的操作
     */
    private static void runAfterEither() {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 2 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future1结果:{}",t);
            return t;
        } );

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync( () -> {
            int t = new Random().nextInt( 2 );
            try {
                TimeUnit.SECONDS.sleep( t );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future2结果:{}",t);
            return t;
        } );
        future1.runAfterEither( future2, () -> log.info("只要有一个任务执行结束,我就会被执行到") );
    }

    /***
     * 两个CompletionStage，都完成了计算才会执行下一步的操作
     */
    private static void runAfterBoth() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> fu1 = CompletableFuture.supplyAsync( () -> {
            int time = new Random().nextInt( 3 );
            try {
                TimeUnit.SECONDS.sleep( time+1 );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future1结果:{}",time);
            return time;
        } );

        CompletableFuture<Integer> fu2 = CompletableFuture.supplyAsync( () -> {
            int time = new Random().nextInt( 3 );
            try {
                TimeUnit.SECONDS.sleep( time+1 );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("future2结果:{}",time);
            return time;
        } );
        fu1.get();
        fu2.get();
        fu1.runAfterBoth( fu2, () -> log.info("当两个任务都执行结束,我就会被执行到") );
    }

    /***
     * thenCompose 方法允许你对两个 CompletionStage 进行流水线操作，第一个操作完成时，将其结果作为参数传递给第二个操作。
     */
    private static void thenCompose() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync( () -> {
            int r = new Random().nextInt( 5 );
            log.info("future1结果:{}",r);
            return r;
        } ).thenCompose( param -> CompletableFuture.supplyAsync( () -> {
            int r = param * 10;
            log.info("thenCompose执行结果:{}",r);
            return r;
        } ) );
        log.info("thenCompose执行结果:{}",future.get());

    }


    public static void main(String[] args) throws ExecutionException, InterruptedException {
       runAsync();
//        supplyAsync();
//        whenComplete();
       CompletableFuture<Void> future = CompletableFuture.runAsync( () -> {
    	   try {
			thenApply();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
       });
       future.get();
//        handle();
//        thenAccept();
     //thenRun();
//        thenCombine();
//        thenAcceptBoth();
//        applyToEither();
//        acceptEither();
//        runAfterEither();
//        runAfterBoth();
//        thenCompose();
    }
}
 